package com.fc.utils;

import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 图片处理工具类（压缩、缩放、旋转、加水印）
 * 基于 Thumbnailator + Java2D，线程安全，资源安全
 */
public class ImageUtil {

    // 默认参数
    private static final float DEFAULT_SCALE_RATIO = 0.5f;
    private static final int DEFAULT_JPEG_QUALITY = 85; // 1-100
    private static final Font DEFAULT_FONT = new Font("微软雅黑", Font.BOLD, 24);
    private static final Color DEFAULT_COLOR = Color.WHITE;
    private static final float DEFAULT_OPACITY = 0.8f;

    /**
     * 压缩图片（默认比例 0.5，JPEG 质量 85）
     *
     * @param file         上传文件
     * @param outputFormat 输出格式：JPEG/PNG
     * @return 压缩后的字节数组
     * @throws IOException 处理失败
     */
    public static byte[] compressImage(MultipartFile file, String outputFormat) throws IOException {
        return resize(file, DEFAULT_SCALE_RATIO, outputFormat);
    }

    /**
     * 批量压缩图片
     *
     * @param files        文件数组
     * @param outputFormat 输出格式
     * @return 每个文件压缩后的字节数组
     * @throws IOException 任一文件失败则抛出
     */
    public static byte[][] batchCompressImages(MultipartFile[] files, String outputFormat) throws IOException {
        byte[][] results = new byte[files.length][];
        for (int i = 0; i < files.length; i++) {
            results[i] = compressImage(files[i], outputFormat);
        }
        return results;
    }

    /**
     * 按比例缩放图片（保持宽高比）
     *
     * @param file         原图
     * @param scaleRatio   缩放比例 (0.01 ~ 10]
     * @param outputFormat 输出格式
     * @return 缩放后图片数据
     * @throws IOException 处理失败
     */
    public static byte[] resize(MultipartFile file, float scaleRatio, String outputFormat) throws IOException {
        validateFile(file);
        validateScaleRatio(scaleRatio);
        String format = validateFormat(outputFormat);

        try (InputStream in = file.getInputStream()) {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            Thumbnails.of(in)
                    .scale(clamp(scaleRatio, 0.01f, 10.0f))
                    .outputFormat(format)
                    .outputQuality(getQuality(format))
                    .toOutputStream(out);
            return out.toByteArray();
        }
    }

    /**
     * 按指定宽高缩放（可能变形）
     *
     * @param file         原图
     * @param width        目标宽度 > 0
     * @param height       目标高度 > 0
     * @param outputFormat 输出格式
     * @return 缩放后数据
     * @throws IOException 处理失败
     */
    public static byte[] resizeToDimension(MultipartFile file, int width, int height, String outputFormat) throws IOException {
        validateFile(file);
        if (width <= 0 || height <= 0) {
            throw new IllegalArgumentException("宽高必须大于 0");
        }
        String format = validateFormat(outputFormat);

        try (InputStream in = file.getInputStream()) {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            Thumbnails.of(in)
                    .size(width, height)
                    .outputFormat(format)
                    .outputQuality(getQuality(format))
                    .toOutputStream(out);
            return out.toByteArray();
        }
    }

    /**
     * 旋转图片
     *
     * @param file         原图
     * @param degrees      角度：90, 180, 270（支持负数）
     * @param outputFormat 输出格式
     * @return 旋转后数据
     * @throws IOException 处理失败
     */
    public static byte[] rotate(MultipartFile file, int degrees, String outputFormat) throws IOException {
        validateFile(file);
        String format = validateFormat(outputFormat);

        try (InputStream in = file.getInputStream()) {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            Thumbnails.of(in)
                    .scale(1.0)
                    .rotate(degrees)
                    .outputFormat(format)
                    .toOutputStream(out);
            return out.toByteArray();
        }
    }

    /**
     * 添加文字水印
     *
     * @param file          原图
     * @param watermarkText 水印文字
     * @param font          字体（null 则用默认）
     * @param color         颜色（null 则白色）
     * @param position      位置（如 BOTTOM_RIGHT）
     * @param opacity       透明度 [0.0 ~ 1.0]
     * @param outputFormat  输出格式
     * @return 加水印后图片数据
     * @throws IOException 处理失败
     */
    public static byte[] addTextWatermark(MultipartFile file, String watermarkText, Font font,
                                          Color color, Positions position, float opacity,
                                          String outputFormat) throws IOException {

        validateFile(file);
        if (watermarkText == null || watermarkText.trim().isEmpty()) {
            throw new IllegalArgumentException("水印文字不能为空");
        }
        String format = validateFormat(outputFormat);
        font = (font != null) ? font : DEFAULT_FONT;
        color = (color != null) ? color : DEFAULT_COLOR;
        opacity = clamp(opacity, 0.0f, 1.0f);
        position = (position != null) ? position : Positions.BOTTOM_RIGHT;

        BufferedImage originalImage;
        try (InputStream in = file.getInputStream()) {
            originalImage = ImageIO.read(in);
            if (originalImage == null) {
                throw new IOException("无法识别的图片格式，请上传有效的图片文件。");
            }
        }

        BufferedImage watermarked = new BufferedImage(
                originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_INT_ARGB);

        Graphics2D g2d = watermarked.createGraphics();
        g2d.drawImage(originalImage, 0, 0, null);

        // 抗锯齿
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2d.setFont(font);
        g2d.setColor(color);
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));

        FontMetrics fm = g2d.getFontMetrics();
        int tw = fm.stringWidth(watermarkText);
        int th = fm.getAscent();
        int x = 0, y = 0;

        switch (position) {
            case BOTTOM_RIGHT:
                x = originalImage.getWidth() - tw - 10;
                y = originalImage.getHeight() - 10;
                break;
            case CENTER:
                x = (originalImage.getWidth() - tw) / 2;
                y = (originalImage.getHeight() + th) / 2;
                break;
            case TOP_LEFT:
                x = 10;
                y = th + 10;
                break;
            case TOP_RIGHT:
                x = originalImage.getWidth() - tw - 10;
                y = th + 10;
                break;
            case BOTTOM_LEFT:
                x = 10;
                y = originalImage.getHeight() - 10;
                break;
            default:
                x = 10;
                y = th + 10;
        }

        g2d.drawString(watermarkText, x, y);
        g2d.dispose();

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        boolean success = ImageIO.write(watermarked, format, out);
        if (!success) {
            throw new IOException("图片写入失败，不支持的格式: " + format);
        }
        return out.toByteArray();
    }


    private static void validateFile(MultipartFile file) throws IOException {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("图片文件不能为空");
        }
        if (file.getSize() > 10 * 1024 * 1024) { // 10MB 限制
            throw new IOException("图片大小不能超过 10MB");
        }
    }

    private static String validateFormat(String format) {
        if (format == null) format = "JPEG";
        format = format.trim().toUpperCase();
        if (!"JPEG".equals(format) && !"JPG".equals(format) && !"PNG".equals(format)) {
            throw new IllegalArgumentException("仅支持 JPEG 和 PNG 格式");
        }
        return "JPEG".equals(format) || "JPG".equals(format) ? "JPEG" : "PNG";
    }

    private static double getQuality(String format) {
        return "JPEG".equalsIgnoreCase(format) ? DEFAULT_JPEG_QUALITY / 100.0 : 1.0;
    }

    private static float clamp(float value, float min, float max) {
        return Math.max(min, Math.min(max, value));
    }

    private static void validateScaleRatio(float scaleRatio) {
        if (scaleRatio <= 0 || scaleRatio > 10) {
            throw new IllegalArgumentException("缩放比例应在 (0, 10] 范围内");
        }
    }
}